package com.iwechat.api.http;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.iwechat.PropertyUtils;
import com.iwechat.httpClient.HttpUtilImpl;
import com.iwechat.httpClient.IHttpUtil;

public class MessageSendAPI {
    private static final Logger         logger       = LoggerFactory.getLogger(MessageSendAPI.class);
    private static final MessageSendAPI instance     = new MessageSendAPI();
    IHttpUtil                           httpUtil     = HttpUtilImpl.getInstance();
    private PropertyUtils               propUtil     = PropertyUtils.getInstance();
    private AtomicInteger               sequenceAto  = new AtomicInteger(0);
    private String                      clientId;
    private String                      clientIp;
    private JSONObject                  jsonTemplate = new JSONObject();

    /**
     * @return the instance
     */
    public static MessageSendAPI getInstance() {
        return instance;
    }

    private MessageSendAPI() {
        try {
            clientIp = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            clientIp = "";
            logger.error(e.getMessage(), e);
        }
        clientId = propUtil.getStringValue("settings", "clientId");

        jsonTemplate.put(ConstEmus.clientIp.value(), clientIp);
        jsonTemplate.put(ConstEmus.clientId.value(), clientId);

        logger.info("### init succeed!");
    }

    /**
     * <b>给多个openid发送消息，并返回该响应List</b>
     * 
     * 
     * @param openids
     *            openid数组
     * @param templateId
     *            服务方提供的模板编号
     * @param fields
     *            有序数组，顺序必须与服务方要求的顺序相同
     * @param urlParams
     *            添加到模板消息详情url后的参数，必须包含key为refid的参数,指对应的关联id
     * @return 返回一个json列表，每个json是一个结果状态
     * @throws Exception
     */
    public List<JSONObject> send2MulityUser(String[] openids, String templateId, String[] fields, Map<String, String> urlParams) throws Exception {
        return this.send2MulityUser(openids, templateId, fields, urlParams, "", "");
    }

    /**
     * <b>给多个openid发送消息，并返回该响应List</b><br>
     * 消息只可以在某个时间段内发送<br>
     * 
     * 
     * @param openids
     *            openid数组
     * @param templateId
     *            服务方提供的模板编号
     * @param fields
     *            有序数组，顺序必须与服务方要求的顺序相同
     * @param urlParams
     *            添加到模板消息详情url后的参数，必须包含key为refid的参数,指对应的关联id
     * @param startTime
     *            期望的消息开发发送时间 HHMMSS
     * @param stopTime
     *            期望的消息停止发送时间 HHMMSS
     * @return 返回一个json列表，每个json是一个结果状态
     * @throws Exception
     */
    public List<JSONObject> send2MulityUser(String[] openids, String templateId, String[] fields, Map<String, String> urlParams, String startTime,
            String stopTime) throws Exception {
        List<JSONObject> ret = null;
        if (openids == null || templateId == null) {
            return null;
        } else {
            ret = new LinkedList<JSONObject>();
            for (String openid : openids) {
                JSONObject o = this.sendSingle(openid, templateId, fields, urlParams, startTime, stopTime);
                ret.add(o);
            }
        }
        return ret;
    }

    /**
     * <b>发送消息并返回该响应Json</b><br>
     * 
     * 
     * @param openid
     *            接收者openid
     * @param templateId
     *            服务方提供的模板编号
     * @param fields
     *            有序数组，顺序必须与服务方要求的顺序相同
     * @param urlParams
     *            添加到模板消息详情url后的参数，必须包含key为refid的参数,指对应的关联id
     * 
     * @return 返回一个json是一个结果状态
     * @throws Exception
     */
    public JSONObject sendSingle(String openid, String templateId, String[] fields, Map<String, String> urlParams) throws Exception {
        return this.sendSingle(openid, templateId, fields, urlParams, "", "");
    }

    /**
     * <b>发送消息并返回该响应Json</b><br>
     * 消息只可以在某个时间段内发送<br>
     * 
     * 
     * @param openid
     *            接收者openid
     * @param templateId
     *            服务方提供的模板编号
     * @param fields
     *            有序数组，顺序必须与服务方要求的顺序相同
     * @param startTime
     *            期望的消息开发发送时间 HHMMSS
     * @param stopTime
     *            期望的消息停止发送时间 HHMMSS
     * @return 返回一个json是一个结果状态
     * @throws Exception
     */
    public JSONObject sendSingle(String openid, String templateId, String[] fields, Map<String, String> urlParams, String startTime, String stopTime)
            throws Exception {
        JSONObject resp = null;
        JSONObject message = packSingle(openid, templateId, fields, urlParams);
        message.put(ConstEmus.startTime.value(), StringUtils.leftPad(startTime, 6, '0'));
        message.put(ConstEmus.stopTime.value(), StringUtils.leftPad(stopTime, 6, '0'));
        resp = sendSingle(message);
        return resp;
    }

    /**
     * <b>发送消息并返回该响应Json</b><br>
     *
     * 
     * @param message
     * @return 返回一个json是一个结果状态
     * @throws Exception
     */
    private JSONObject sendSingle(JSONObject message) throws Exception {
        JSONObject resp = null;
        String url = propUtil.getStringValue("settings", "wctmps.single.url");

        int sequence = sequenceAto.incrementAndGet();
        if (sequence > Integer.MAX_VALUE - 10000) {
            sequenceAto.set(0);
            sequence = 0;
        }
        message.put(ConstEmus.sequence.value(), sequence);
        String respStr = httpUtil.sendPost(url, message.toJSONString(), String.valueOf(sequence) + "\t");
        resp = JSONObject.parseObject(respStr);
        return resp;
    }

    /**
     * 生成单条模板消息JSON报文
     * 
     * @param openid
     *            封装到 openid中
     * @param templateId
     *            封装到 templateId中
     * @param fields
     *            封装到 fields中
     * @param urlParams
     *            封装到 params中
     * @return 返回一个json是一个结果状态
     */
    private JSONObject packSingle(String openid, String templateId, String[] fields, Map<String, String> urlParams) {
        JSONObject json = (JSONObject) jsonTemplate.clone();
        if (fields != null && templateId != null) {
            json.put(ConstEmus.templateId.value(), templateId);
            json.put(ConstEmus.openid.value(), openid);
            JSONObject _fileds = new JSONObject(fields.length);
            json.put(ConstEmus.filedSize.value(), fields.length);
            json.put(ConstEmus.fileds.value(), _fileds);
            for (int i = 0; i < fields.length; i++) {
                _fileds.put(ConstEmus.filed_.value() + (i + 1), fields[i]);
            }
            if (urlParams != null && urlParams.size() > 0) {
                JSONObject paramJson = new JSONObject();
                for (Entry<String, String> e : urlParams.entrySet()) {
                    paramJson.put(e.getKey(), e.getValue());
                }
                json.put(ConstEmus.params.value(), paramJson);
            }
        }

        return json;
    }

    /**
     * @return the clientId
     */
    public String getClientId() {
        return clientId;
    }

    /**
     * @param clientId
     *            the clientId to set
     */
    public void setClientId(String clientId) {
        this.clientId = clientId;
    }
}
